package concurrency.chapter3;

import java.util.concurrent.TimeUnit;

/**
 * 包装了一个线程类,主要用于控制一些比较耗时的操作
 * 比如一个IO操作,我期望30分钟内如果没有执行完成,线程就停止执行
 * 虽然可以调用线程的stop()方法,但是已经被JDK弃用,所以自己封装了一个,可以实现类似功能的类
 *
 *
 * @author honway.liu
 * @date 2019-06-05 00:03
 * @email gm100861@gmail.com
 * @blog http://linuxsogood.org
 */
public class ThreadForceCloseDemo {

    static class ExecuteServiceWrapper {

        // 执行任务线程
        private Thread executeThread;

        // 标识符,标识线程任务有没有执行完成
        private volatile boolean finished = false;

        /**
         * 开启一个线程,执行给定的任务
         * executeThread 是一个普通进程, 主要用于控制做任务的终止,即关闭线程
         * 实现是在executeThread线程内,创建了一个守护线程,并用这个守护线程去执行具体的业务逻辑
         * 我们知道守护线程是守护普通线程的,如果普通线程关闭,那么守护线程不管任务有没有执行完成,都会一起关闭
         * 我们使用守护线程来执行任务,让他来守护外线的控制线程,如果我们关闭外面的控制线程,那么守护线程会由于没有可守护的普通线程
         * 而随之一起被关闭,从而实现强制关闭线程并终止任务的目的. 我们在守护线程,使用了join方法,表示守护线程必须任务执行完毕,才会执行
         * 外面的非守护线程
         * @param task 要执行的任务
         */
        public void submit(Runnable task) {
            executeThread = new Thread(() -> {
                Thread runnerTask = new Thread(task);
                runnerTask.setDaemon(true);
                runnerTask.start();

                try {
                    runnerTask.join();
                    finished = true;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });

            executeThread.start();
        }

        /**
         * 关闭线程并终止执行任务
         * 任务超时未执行完,是通过调用executeThread的中止方法来实现的,因为该线程有一个守护线程,任务是放在守护线程中的
         * 当executeThread线程被中止的时候,它里面的守护线程会因为没有可守护的线程,会随之一起被关闭掉.
         * @param timeout 超时时间, 如果超过了这个时间任务还没有执行完成,那么就强制终止任务,关闭线程
         */
        public void shutdown(long timeout) {
            long currentTimeMillis = System.currentTimeMillis();
            while (!finished) {
                if (System.currentTimeMillis() - currentTimeMillis > timeout) {
                    // 任务超时未执行完
                    System.out.println("任务执行超时");
                    executeThread.interrupt();
                    break;
                }
                // 任务没超时,还在执行.
                try {
                    TimeUnit.MILLISECONDS.sleep(10);
                } catch (InterruptedException e) {
                    // shutdown被打断.
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {
        ExecuteServiceWrapper serviceWrapper = new ExecuteServiceWrapper();
        serviceWrapper.submit(() -> {
            try {
                /*
                while (true) {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println("task is running");
                }*/
                System.out.println("task is running");
                TimeUnit.SECONDS.sleep(3);
                System.out.println("task is finished");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        serviceWrapper.shutdown(8000);

    }

}
